package com.wpen.unit.core.pool;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;

import com.wpen.unit.core.cache.TaskExecContext;
import com.wpen.unit.AppVariables;
import com.wpen.unit.core.cache.TaskExecProcess;
import com.wpen.unit.enums.ExecStatus;
import com.wpen.unit.utils.JsonUtil;
import com.wpen.unit.utils.OsUtil;
import com.wpen.unit.web.WebVariables;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * 
 * 
 * @author Wang Peng
 * @date 2022-12-04
 */
@Slf4j
public class TaskExecRunner implements Callable<TaskExecContext> {
    private TaskExecContext taskRunContext;

    public TaskExecRunner(TaskExecContext taskRunContext) {
        this.taskRunContext = taskRunContext;
        this.taskRunContext.setStatus(ExecStatus.Init);
    }

    @Override
    public TaskExecContext call() throws Exception {
        try {
            // 执行中
            this.taskRunContext.setStatus(ExecStatus.Running);
            this.taskRunContext.setStartDate(new Date());
            // 执行子任务
            List<String> infos = new LinkedList<>();
            List<String> errors = new LinkedList<>();
            String cmd = taskRunContext.getCmd();
            String param = taskRunContext.getParams();
            param = param.replaceAll("\"", "\\\\\"");
            String[] cmds =  cmd.split(" ");
            String[] cmds2 =  new String[cmds.length + 1];
            for (int i = 0; i < cmds.length; i++) {
            	cmds2[i] = cmds[i];
			}
            cmds2[cmds2.length - 1] = param;
            log.info("CMD>>>>>run>>> " + JsonUtil.toJson(cmds2) );

            String charset = OsUtil.getOsCharset();
            // 执行脚本
            Process ps = Runtime.getRuntime().exec(cmds2);
            long pid = 0L;
            if (AppVariables.jdkLargeVersion >= 11) {
                pid = ps.pid();
            }
            
            TaskExecProcess.getInstance().putProcess(taskRunContext.getKey(), ps);
            
            this.taskRunContext.setPid(pid);
            // 只能接收脚本echo打印的数据，并且是echo打印的最后一次数据
            BufferedInputStream in = new BufferedInputStream(ps.getInputStream());
            BufferedReader br = new BufferedReader(new InputStreamReader(in, Charset.forName(charset)));
            // 只能接收脚本echo打印的数据，并且是echo打印的最后一次数据
            BufferedInputStream error = new BufferedInputStream(ps.getErrorStream());
            BufferedReader brerror = new BufferedReader(new InputStreamReader(error, Charset.forName(charset)));

            String line;
            while (ps.isAlive() && (line = br.readLine()) != null) {
                System.out.println("[" + pid + "]>" + line);
                // 信息不读取出来，缓冲区满了会堵塞，永远也不会结束了。。。
                // getInputStream流信息不保留，也可以输出到文件。
                infos.add(line + "\n");
                if (infos.size() > 100) {
                    infos.remove(0);
                }
            }
            in.close();
            br.close();

            String lineError;
            while ((lineError = brerror.readLine()) != null) {
                System.out.println("[" + pid + "]>" + lineError);
                errors.add(lineError + "\n");
                if (errors.size() > 200) {
                    errors.remove(0);
                }
            }
            error.close();
            brerror.close();
            int exitValue = ps.waitFor();
            System.out.println("===" + pid + ">>" + exitValue);
            if (exitValue != 0) {
                // 不是0就是异常了
                if (errors.isEmpty()) {
                    errors.addAll(infos);
                }
            }

            taskRunContext.setExitValue(exitValue);
            // contextResponse.setResult(result.toString());
            if (errors == null || errors.isEmpty()) {
                this.taskRunContext.setStatus(ExecStatus.Finished);
                taskRunContext.setRtnCode(WebVariables.RESPONSE_SUCC_CODE);
                taskRunContext.setRtnMsg(WebVariables.RESPONSE_SUCC_MSG);
            } else {
                this.taskRunContext.setStatus(ExecStatus.Excption);
                taskRunContext.setRtnCode(WebVariables.RESPONSE_AGENT_EXCEPTION);
                taskRunContext.setRtnMsg("任务作业[" + taskRunContext.getKey() + "]执行异常");
                taskRunContext.setErrors(errors.toString());
            }
        } catch (Exception e) {
            this.taskRunContext.setStatus(ExecStatus.Excption);
            // 给子任务添加异常码，及异常信息
            this.taskRunContext.setRtnCode(WebVariables.RESPONSE_AGENT_EXCEPTION);
            this.taskRunContext.setRtnMsg(e.getMessage());
            log.error("任务作业[" + taskRunContext.getKey() + "]执行异常.", e);
        } finally {
            this.taskRunContext.setEndDate(new Date());
            TaskExecProcess.getInstance().removeProcess(taskRunContext.getKey());
        }
        // 任务执行完，通知调用平台结果
        System.out.println("TaskExecRunner,,Finished>>>>>" + this.taskRunContext.getKey());
        return this.taskRunContext;
    }

}
